from django.db import models
from django.conf import settings
import datetime

class ChangeSetManager(models.Manager):
    """
    Manager class for changesets.
    """
    def get_or_create(self):
        """Utility to create a new changeset."""
        try:
            self.filter(syncroot=settings.LOCAL_SYNCROOT).filter(closed__isnull=True).get() # this should never return multuple results because of the unique_together key.
        except ChangeSet.DoesNotExist:
            revision = 1 + self.filter(syncroot=settings.LOCAL_SYNCROOT).count()
            return self.create(syncroot=settings.LOCAL_SYNCROOT,revision=revision)

class ChangeSet(models.Model):
    """
    Represents a commit of the data model.  An 'open' changeset has a null
    closed field.  Because there is a unique composite key on syncroot and
    the closed field, there can therefore only be one open changeset per
    syncroot at a time.
    """
    syncroot = models.CharField()
    revision = models.IntegerField()
    opened = models.DateTimeField(default=datetime.datetime.new())
    closed = models.DateTimeField(blank=True,null=True)
    
    objects = ChangeSetManager()
    
    def commit(self):
        """Closes out this changeset."""
        self.closed = datetime.datetime.now()
        self.save()
    
    class Meta:
        unique_together = (('syncroot','revision'),('syncroot','closed'))

class Synchronizable(models.Model):
    """
    Abstract base class that provides synchronization services.
    """
    changeset = models.ForeignKey(ChangeSet,related_name='%(class)s_synchronizables')
    
    def save(self):
        """Save overridden in order to mutate changeset reference to whatever the open changeset might be."""
        self.changeset = ChangeSet.objects.get_or_create()
        return super(Synchronizable,self).save()
    
    def save_canonical(self):
        return super(Synchronizable,self).save() # bypass the changeset mutation
    
    class Meta:
        abstract = True

